package com.project.frame.common.utils.okhttp;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import okhttp3.*;
import okhttp3.logging.HttpLoggingInterceptor;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;

import javax.net.ssl.*;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.security.SecureRandom;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * desc
 *
 * @author cjq
 * @date 2021/12/27
 */
public class OKHttpUtil {

    private static final Logger log = LoggerFactory.getLogger(OKHttpUtil.class);

    private OkHttpClient okHttpClient;

    // 请求格式
    private MediaType mediaType;

    private static final MediaType MEDIA_TYPE_FILE = MediaType.parse("multipart/form-data");

    /**
     * 构造函数
     */
    public OKHttpUtil() {
        init(null, "json");
    }

    /**
     * 构造函数
     *
     * @param interceptor 拦截器
     * @param type 请求类型：json或xml等
     */
    public OKHttpUtil(Interceptor interceptor, String type) {
        init(interceptor, type);
    }

    /**
     * 初始化
     *
     * @param interceptor 拦截器
     * @param type 请求类型：json或xml等
     */
    private void init(Interceptor interceptor, String type) {
        HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BASIC);
        OkHttpClient.Builder mBuilder = new OkHttpClient.Builder();
        mBuilder.connectTimeout(300, TimeUnit.SECONDS);
        mBuilder.readTimeout(300, TimeUnit.SECONDS);
        mBuilder.writeTimeout(300, TimeUnit.SECONDS);
        mBuilder.addInterceptor(loggingInterceptor);
        if (interceptor != null) {
            mBuilder.addInterceptor(interceptor);
        }
        mBuilder.sslSocketFactory(createSSLSocketFactory(), new TrustAllCerts());
        mBuilder.hostnameVerifier(new HostnameVerifier() {
            @Override
            public boolean verify(String hostname, SSLSession session) {
                return true;
            }
        });
        okHttpClient = mBuilder.build();
        type = StringUtils.defaultIfEmpty(type, "json");
        String header = "application/" + type + "; charset=utf-8";
        mediaType = MediaType.parse(header);
    }

    /**
     * 表单提交
     *
     * @param url 请求地址
     * @param paramsMap 请求参数
     * @return Response 返回结果
     */
    public Response postForm(String url, Map<String, Object> paramsMap) {
        FormBody.Builder formBody = new FormBody.Builder();
        if (paramsMap != null) {
            for (String key : paramsMap.keySet()) {
                formBody.add(key, ObjectUtils.toString(paramsMap.get(key)));
            }
        }
        RequestBody requestBody = formBody.build();
        Request request = new Request.Builder().url(url).addHeader("content-type", "application/json; charset=utf-8").post(requestBody)
                .build();
        try {
            Response response = okHttpClient.newCall(request).execute();
            if (response.isSuccessful()) {
                return response;
            }
        } catch (IOException e) {
            log.error("提交表单数据失败：" + e.getMessage(), e);
        }
        return null;
    }

    /**
     * 表单提交
     *
     * @param url 请求地址
     * @param paramsMap 请求参数
     * @return Response 返回结果
     */
    public String postFormWithToken(String url, Map<String, Object> paramsMap, String token) {
        FormBody.Builder formBody = new FormBody.Builder();
        if (paramsMap != null) {
            for (String key : paramsMap.keySet()) {
                formBody.add(key, ObjectUtils.toString(paramsMap.get(key)));
            }
        }
        RequestBody requestBody = formBody.build();
        Request request = new Request.Builder().url(url).addHeader("content-type", "application/json; charset=utf-8").addHeader("access_token", token).post(requestBody)
                .build();
        try {
            Response response = okHttpClient.newCall(request).execute();
            if (response.isSuccessful()) {
                return response.body().string();
            }
        } catch (IOException e) {
            log.error("提交表单数据失败：" + e.getMessage(), e);
        }
        return null;
    }

    /**
     * POST请求
     *
     * @param url 请求地址
     * @param params 参数
     * @return String 返回结果
     */
    public String post(String url, String params) {
        RequestBody body = RequestBody.create(mediaType, params);
        Request request = new Request.Builder().url(url).post(body).build();
        return execute(request);
    }

    /**
     * POST请求
     *
     * @param url 请求地址
     * @param params 参数
     * @return String 返回结果
     */
    public String postWithToken(String url, String params, String token) {
        RequestBody body = RequestBody.create(mediaType, params);
        Request request = new Request.Builder().url(url).addHeader("access_token", token).post(body).build();
        return execute(request);
    }

    /**
     * DELETE请求
     *
     * @param url 请求地址
     * @param params 参数
     * @return String 返回结果
     */
    public String delete(String url, String params) {
        RequestBody body = null;
        if (StringUtils.isNotEmpty(params)) {
            body = RequestBody.create(mediaType, params);
        }
        Request request = null;
        if (body != null) {
            request = new Request.Builder().url(url).delete(body).build();
        } else {
            request = new Request.Builder().url(url).delete().build();
        }
        return execute(request);
    }

    /**
     * DELETE请求
     *
     * @param url 请求地址
     * @param params 参数
     * @return String 返回结果
     */
    public String deleteWithToken(String url, String params, String token) {
        RequestBody body = null;
        if (StringUtils.isNotEmpty(params)) {
            body = RequestBody.create(mediaType, params);
        }
        Request request = null;
        if (body != null) {
            request = new Request.Builder().url(url).delete(body).build();
        } else {
            request = new Request.Builder().url(url).delete().build();
        }
        return execute(request);
    }

    /**
     * GET请求
     *
     * @param url 请求地址
     * @return String 返回结果
     */
    public String get(String url) {
        Request request = new Request.Builder().url(url).build();
        return execute(request);
    }

    /**
     * GET请求(带参数的)
     *
     * @param url 请求地址
     * @param params 参数
     * @return String 返回结果
     */
    public String get(String url, Map<String, Object> params) {
        Request.Builder reqBuild = new Request.Builder();
        HttpUrl.Builder urlBuilder = HttpUrl.parse(url).newBuilder();
        for (Map.Entry<String, Object> entry : params.entrySet()) {
            urlBuilder.addQueryParameter(entry.getKey(), entry.getValue() + "");
        }
        reqBuild.url(urlBuilder.build());
        return execute(reqBuild.url(urlBuilder.build()).build());
    }

    public String get(String url, Map<String, Object> params,Map<String,String> headMap) {
        Request.Builder reqBuild = new Request.Builder();
        HttpUrl.Builder urlBuilder = HttpUrl.parse(url).newBuilder();
        if(params!=null && params.size()>0){
            for (Map.Entry<String, Object> entry : params.entrySet()) {
                urlBuilder.addQueryParameter(entry.getKey(), entry.getValue() + "");
            }
        }
        if(headMap!=null && headMap.size()>0){
            headMap.keySet().stream().forEach(key->{
                reqBuild.addHeader(key,headMap.get(key));
            });
        }
        reqBuild.url(urlBuilder.build());
        return execute(reqBuild.url(urlBuilder.build()).build());
    }

    /**
     * GET请求
     *
     * @param url 请求地址
     * @return String 返回结果
     */
    public InputStream getStream(String url) {
        Request request = new Request.Builder().url(url).build();
        return executeStream(request);
    }

    /**
     * PATCH请求
     *
     * @param url 请求地址
     * @param params 请求参数
     * @return String 返回结果
     */
    public String patch(String url, String params) {
        RequestBody body = RequestBody.create(mediaType, params);
        Request request = new Request.Builder().url(url).patch(body).build();
        return execute(request);
    }

    /**
     * PUT请求
     *
     * @param url 请求地址
     * @param params 请求参数
     * @return String 返回结果
     */
    public String put(String url, String params) {
        RequestBody body = RequestBody.create(mediaType, params);
        Request request = new Request.Builder().url(url).put(body).build();
        return execute(request);
    }

    public String putJson(String url, Map<String,Object> jsonMap,Map<String,String> headMap) {
        Request.Builder builder = new Request.Builder();
        RequestBody body = RequestBody.create(mediaType, JSON.toJSONString(jsonMap));
        if(headMap!=null){
            headMap.keySet().stream().forEach(key->{
                builder.addHeader(key,headMap.get(key));
            });
        }
        return execute(builder.url(url).addHeader("content-type", "application/json").put(body).build());

    }

    /**
     * 处理请求
     *
     * @param request 请求内容
     * @return String 返回结果
     */
    private String execute(Request request) {
        try {
            Response response = okHttpClient.newCall(request).execute();
            if (response.isSuccessful()) {
                return response.body().string();
            }
        } catch (java.net.ConnectException | java.net.SocketTimeoutException e) {
            log.error("Okhttp请求失败：" + e.getMessage());
        } catch (Exception e) {
            log.error("Okhttp请求失败：" + e.getMessage(), e);
        }
        return null;
    }

    /**
     * 处理请求
     *
     * @param request 请求内容
     * @return InputStream 返回结果
     */
    private InputStream executeStream(Request request) {
        try {
            Response response = okHttpClient.newCall(request).execute();
            if (response.isSuccessful()) {
                return response.body().byteStream();
            }
        } catch (IOException e) {
            log.error("Okhttp请求失败：" + e.getMessage(), e);
            return null;
        }
        return null;
    }

    /**
     * 创建SSL
     *
     * @return SSLSocketFactory 返回SSL工厂类
     */
    private SSLSocketFactory createSSLSocketFactory() {
        SSLSocketFactory ssfFactory = null;
        try {
            SSLContext sc = SSLContext.getInstance("TLS");
            sc.init(null, new TrustManager[] { new TrustAllCerts() }, new SecureRandom());
            ssfFactory = sc.getSocketFactory();
        } catch (Exception e) {
        }
        return ssfFactory;
    }


    //cjianquan 2021/4/15
	/*@Deprecated
	public String post(String url, String params,Map<String,String> headMap) {
		RequestBody body = RequestBody.create(mediaType, params);
		Request.Builder builder = new Request.Builder();
		if(headMap!=null){
			headMap.keySet().stream().forEach(key->{
				builder.addHeader(key,headMap.get(key));
			});
		}
		Request request = builder.url(url).post(body).build();
		return execute(request);
	}*/

	/*@Deprecated
	public String postWithFiles(String url, Map<String, Object> paramsMap, List<MultipartFile> files){
		String result = null;
		try{
			MultipartBody.Builder builder = new MultipartBody.Builder();

			builder.setType(MultipartBody.FORM);
			for (MultipartFile file : files) {
				String fileName = file.getOriginalFilename();
				File sendFile = new File(System.getProperty("java.io.tmpdir") + File.separator+ "tmp-" + fileName + "");
				file.transferTo(sendFile);
				MediaType mediaType = okhttp3.MediaType.parse(org.springframework.http.MediaType.APPLICATION_OCTET_STREAM_VALUE);
				RequestBody fileBody = RequestBody.create(mediaType, sendFile);
				builder.addFormDataPart("file",fileName, fileBody);
			}
			if (paramsMap != null) {
				for (String key : paramsMap.keySet()) {
					builder.addFormDataPart(key, ObjectUtils.toString(paramsMap.get(key)));
				}
			}
			RequestBody requestBody = builder.build();
			Request request = new Request.Builder().post(requestBody).url(url)
					.addHeader("Content-Type", org.springframework.http.MediaType.MULTIPART_FORM_DATA_VALUE)
					.build();
			Response response = okHttpClient.newCall(request).execute();
			if (response != null && response.isSuccessful()) {
				result = response.body().string();
			}
		}catch (Exception e){
			e.printStackTrace();
		}
		return result;
	}*/


    public String postWithFiles(String url, Map<String, Object> paramsMap,
                                Map<String,String> headMap, List<MultipartFile> files){
        String result = null;
        try{
            MultipartBody.Builder builder = new MultipartBody.Builder();

            builder.setType(MultipartBody.FORM);
            for (MultipartFile file : files) {
                String fileName = file.getOriginalFilename();
                File sendFile = new File(System.getProperty("java.io.tmpdir") + File.separator+ "tmp-" + fileName + "");
                file.transferTo(sendFile);
                MediaType mediaType = MediaType.parse(org.springframework.http.MediaType.APPLICATION_OCTET_STREAM_VALUE);
                RequestBody fileBody = RequestBody.create(mediaType, sendFile);
                builder.addFormDataPart("file",fileName, fileBody);
            }
            if (paramsMap != null) {
                for (String key : paramsMap.keySet()) {
                    builder.addFormDataPart(key, ObjectUtils.toString(paramsMap.get(key)));
                }

            }
            Request.Builder reqBuilder = new Request.Builder();
            if(headMap!=null){
                headMap.keySet().stream().forEach(key->{
                    reqBuilder.addHeader(key,headMap.get(key));
                });
            }

            RequestBody requestBody = builder.build();
            Request request = reqBuilder.post(requestBody).url(url)
                    .addHeader("Content-Type", org.springframework.http.MediaType.MULTIPART_FORM_DATA_VALUE)
                    .build();
            Response response = okHttpClient.newCall(request).execute();
            if (response != null && response.isSuccessful()) {
                result = response.body().string();
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return result;
    }

    /**
     *
     * @author cjianquan
     * @date 2021/5/31
     */
    public String postForm(String url, Map<String, Object> paramsMap,Map<String,String> headMap) {
        FormBody.Builder formBody = new FormBody.Builder();
        if (paramsMap != null) {
            for (String key : paramsMap.keySet()) {
                formBody.add(key, ObjectUtils.toString(paramsMap.get(key)));
            }
        }
        Request.Builder builder = new Request.Builder();
        if(headMap!=null){
            headMap.keySet().stream().forEach(key->{
                builder.addHeader(key,headMap.get(key));
            });
        }

        RequestBody requestBody = formBody.build();
        Request request = builder.url(url).addHeader("content-type", "application/json").post(requestBody)
                .build();
        try {
            Response response = okHttpClient.newCall(request).execute();
            if (response!=null && response.isSuccessful()) {
                return response.body().string();
            }
        } catch (IOException e) {
            log.error("提交表单数据失败：" + e.getMessage(), e);
        }
        return null;
    }

    /**
     *
     * @author cjianquan
     * @date 2021/6/1
     * @param url :
     * @param queryMap :
     * @param headMap :
     * @return : java.lang.String
     */
    public String post(String url,Map<String,Object> queryMap,Map<String,String> headMap){
        Request.Builder builder = new Request.Builder();
        HttpUrl.Builder urlBuilder = HttpUrl.parse(url).newBuilder();
        for (Map.Entry<String, Object> entry : queryMap.entrySet()) {
            urlBuilder.addQueryParameter(entry.getKey(), entry.getValue() + "");
        }
        if(headMap!=null){
            headMap.keySet().stream().forEach(key->{
                builder.addHeader(key,headMap.get(key));
            });
        }
        RequestBody body= RequestBody.create(null,new byte[0]);
        return execute(builder.url(urlBuilder.build()).post(body).build());
    }

    public String postJson(String url,Map<String,Object> jsonMap,Map<String,String> headMap){
        Request.Builder builder = new Request.Builder();
        RequestBody body = RequestBody.create(mediaType, JSON.toJSONString(jsonMap));
        if(headMap!=null){
            headMap.keySet().stream().forEach(key->{
                builder.addHeader(key,headMap.get(key));
            });
        }
        return execute(builder.url(url).addHeader("content-type", "application/json").post(body).build());
    }

    public Response requestByForm(String url, Map<String, Object> paramsMap, Map<String, String> headMap, String method) {
        Request.Builder builder = new Request.Builder();
        if(headMap!=null && headMap.size()>0){
            headMap.keySet().stream().forEach(key->{
                builder.addHeader(key,headMap.get(key));
            });
        }
        log.info(JSONObject.toJSONString(paramsMap));
        RequestBody body = RequestBody.create(mediaType, JSONObject.toJSONString(paramsMap));
        Request request  = builder.url(url)
                .addHeader("content-type", "application/json; charset=utf-8")
                .post(body)
                .build();



        try {
            Response response = okHttpClient.newCall(request).execute();
            return response;
        } catch (IOException e) {
            log.error("提交表单数据失败：" + e.getMessage(), e);
        }
        return null;
    }

}
